package com.fits.gateway.api.config;

import cn.hutool.core.util.StrUtil;
import com.fits.gateway.api.contsants.AuthConstants;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Component
public class AuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {
    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
        ServerHttpRequest request = authorizationContext.getExchange().getRequest();
        //白名单标识
        String ignore = request.getHeaders().getFirst(AuthConstants.IGNORE_URL);
        if (StrUtil.isNotBlank(ignore) && "1".equals(ignore)) {
            return Mono.just(new AuthorizationDecision(true));
        }
        //跨域的预检请求
        if (request.getMethod() == HttpMethod.OPTIONS) {
            return Mono.just(new AuthorizationDecision(true));
        }
        //经过了过滤器的token的校验了
        String bearerToken = request.getHeaders().getFirst(AuthConstants.JWT_TOKEN_HEADER);
        if (StrUtil.isBlank(bearerToken)) {
            return Mono.just(new AuthorizationDecision(false));
        }
        String token = bearerToken.replace(AuthConstants.JWT_TOKEN_PREFIX, "");
        //此处鉴权拿的是认证之后的权限列表
        return mono
                //过滤认证通过的
                .filter(Authentication::isAuthenticated)
                //权限列表
                .flatMapIterable(Authentication::getAuthorities)
                //提取getAuthority权限字符
                .map(GrantedAuthority::getAuthority)
                //检查权限是否符合条件
                .any(s -> true)
                //如果存在权限，则映射为一个AuthorizationDecision对象
                .map(AuthorizationDecision::new)
                //默认未授权
                .defaultIfEmpty(new AuthorizationDecision(false));
    }
}
